import cv2 as cv  # 导入 OpenCV 库，用于图片处理和计算机视觉任务
import numpy as np  # 导入 numpy 库，用于进行数值计算

class DocScanner:
    def __init__(self):
        pass  # DocScanner 的初始化方法，目前为空

    def load_image(self, file_path):
        """加载图片并找到文档的四个角落。"""
        img = cv.imread(file_path)  # 读取图片（补全此行）
        if img is None:
            raise ValueError(f"无法加载图片: {file_path}")
        
        img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)  # 将图片转换为灰度图（补全此行）
        # 对灰度图进行二值化，得到二值图
        thresh, binary_img = cv.threshold(img_gray, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)  # 补全此行
        # 找到二值图的所有轮廓
        contours, hierarchy = cv.findContours(binary_img, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)  # 补全此行
        
        # 找到最大的周长的四边形的四个顶点 extreme_pnts
        max_perimeter = 0
        extreme_pnts = None
        for contour in contours:
            perimeter = cv.arcLength(contour, True)
            approx = cv.approxPolyDP(contour, 0.02 * perimeter, True)
            if len(approx) == 4 and perimeter > max_perimeter:
                max_perimeter = perimeter
                extreme_pnts = approx
        
        # 若未找到轮廓，默认使用图像四角
        if extreme_pnts is None:
            h, w = img.shape[:2]
            extreme_pnts = np.array([[[0, 0]], [[w, 0]], [[w, h]], [[0, h]]])
        
        corners = self.order_points(extreme_pnts.reshape(4, 2))  # 对四个顶点进行排序
        return img, corners  # 返回图片和排序后的顶点

    def order_points(self, pts):
        """对给定的四个点进行排序，返回排序后的点。"""
        rect = np.zeros((4, 2), dtype="float32")  # 初始化排序后的点为全零
        s = pts.sum(axis=1)  # 计算每个点的坐标和
        rect[0] = pts[np.argmin(s)]  # 左上角的点坐标和最小的那个点
        rect[2] = pts[np.argmax(s)]  # 右下角的点坐标和最大的那个点
        diff = np.diff(pts, axis=1)  # 计算每个点的坐标差
        rect[1] = pts[np.argmin(diff)]  # 右上角的点坐标差最小的那个点
        rect[3] = pts[np.argmax(diff)]  # 左下角的点坐标差最大的那个点

        print(f"0:左上角:{rect[0]},因为x,y的坐标和是: np.min(s)={np.min(s)}")
        print(f"1:右上角:{rect[1]},因为x,y的坐标差是: np.min(diff)={np.min(diff)}")
        print(f"2:右下角:{rect[2]},因为x,y的坐标和是: np.max(s)={np.max(s)}")
        print(f"3:左下角:{rect[3]},因为x,y的坐标差是: np.max(diff)={np.max(diff)}")

        return rect  # 返回排序后的点

    def crop_image(self, img, corners):
        """根据四个角落裁剪图片。"""
        top_left_corner = corners[0]
        top_right_corner = corners[1]
        bottom_right_corner = corners[2]
        bottom_left_corner = corners[3]

        # 计算目标图片的宽度和高度
        width, height = self.get_image_dimensions((top_left_corner, top_right_corner, bottom_right_corner, bottom_left_corner))  

        # 根据宽度和高度创建目标四个点的坐标
        dst_points = np.float32([
            [0, 0],  # 左上
            [width - 1, 0],  # 右上
            [width - 1, height - 1],  # 右下
            [0, height - 1]  # 左下
        ])
            
        # 通过投影变换展平文档
        M = cv.getPerspectiveTransform(corners, dst_points)
        dst = cv.warpPerspective(img, M, (width, height))
        return dst  # 返回展平后的图像

    def get_image_dimensions(self, corners):
        """计算图片的宽度和高度。"""
        top_left, top_right, bottom_right, bottom_left = corners
        
        # 计算宽度（上下边的最大值）
        width_top = np.linalg.norm(top_right - top_left)
        width_bottom = np.linalg.norm(bottom_right - bottom_left)
        max_width = max(int(width_top), int(width_bottom))
        
        # 计算高度（左右边的最大值）
        height_left = np.linalg.norm(bottom_left - top_left)
        height_right = np.linalg.norm(bottom_right - top_right)
        max_height = max(int(height_left), int(height_right))
        
        return max_width, max_height

